package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.remark.LikesClients;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.ReplyDTO;
import com.tianji.learning.domain.query.ReplyPageQuery;
import com.tianji.learning.domain.vo.ReplyVO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.tianji.learning.service.IInteractionReplyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author XinxuanZhuo
 * @since 2024-02-27
 */
@SuppressWarnings("ALL")
@Service
@RequiredArgsConstructor
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {

    // 问题服务
    private final IInteractionQuestionService questionService;

    // 用户远程微服务
    private final UserClient userClient;

    // 点赞微服务
    private final LikesClients likesClient;


    /**
     * 新增回答或评论
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addReply(ReplyDTO dto) {
        // 获取当前用户
        Long userId = UserContext.getUser();
        // 保存回答或者评论到reply表
        InteractionReply reply = BeanUtils.copyBean(dto, InteractionReply.class);
        reply.setUserId(userId);
        this.save(reply);
        //查出问题DO
        InteractionQuestion questionDO = questionService.getById(dto.getQuestionId());
        if (questionDO == null) {
            throw new BadRequestException("问题ID参数错误");
        }
        // 获取answerId作为分支条件
        Long answerId = dto.getAnswerId();
        boolean itsReply = answerId != null;
        // answerId不是null，说明这次操作是评论，则根据answerId对reply表下的回答进行评论数加一的更新
        if (itsReply) {
            // 评论逻辑
            boolean update = lambdaUpdate()
                    .eq(InteractionReply::getId, answerId)
                    .setSql("reply_times = reply_times + 1")
                    .update();
            if (!update) {
                throw new DbException("数据库操作失败");
            }
        }
        // 如果answerId为空，则说明是回答【因为评论是根据答案（回答）去表态】（修改问题表的lastAnswerId）
        // 如果是学生提交，则修改question表的status为未查看，老师提交设置为已查看（default是未查看，文档错了吧，不需要判断学生，但是这里我都写了）
        Boolean itsStudent = dto.getIsStudent();
        boolean update = questionService.lambdaUpdate()
                .eq(InteractionQuestion::getId, questionDO.getId())
                .set(!itsReply, InteractionQuestion::getLatestAnswerId, reply.getId())
                .setSql(!itsReply, "answer_times = answer_times + 1")
                // 以下不管是评论还是问答都是要更新的字段
                .set(!itsStudent, InteractionQuestion::getStatus, QuestionStatus.CHECKED)
                .set(itsStudent, InteractionQuestion::getStatus, QuestionStatus.UN_CHECK)
                .update();
        if (!update) {
            throw new DbException("数据库操作失败");
        }
        return true;
    }


    /**
     * 用户端分页查询问题下的回答或者评论
     */
    @Override
    public PageDTO<ReplyVO> queryAnswerOrReply(ReplyPageQuery query) {
        // 条件分页查询
        LambdaQueryWrapper<InteractionReply> wrapper = this.buildAnswerOrReplyWrapper(query, false);
        Page<InteractionReply> page = this.page(query.toMpPageDefaultSortByCreateTimeDesc(), wrapper);
        // 获取回答或者评论数据
        List<InteractionReply> repliesOrAnswers = page.getRecords();
        // 空直接返回
        if (CollUtils.isEmpty(repliesOrAnswers)) {
            return PageDTO.empty(page);
        }

        // 取出用户id 调用user-service查出用户信息  对于评论有特有的targetUserId需要查出targetUserName
        Boolean itsReply = query.getAnswerId() != null && query.getQuestionId() == null;
        Map<Long, UserDTO> userInfoMap = getUserInfoMapByUserIds(repliesOrAnswers, itsReply);

        // 取出所有的评论或者回答ID，调用远程微服务，判断当前用户是否点过赞
        Set<Long> bizLiked = this.isBizUserLiked(repliesOrAnswers);

        // 封装vo
        List<ReplyVO> voList = new ArrayList<>();
        for (InteractionReply rOra : repliesOrAnswers) {
            // 拷贝
            ReplyVO vo = BeanUtils.copyBean(rOra, ReplyVO.class);
            // 点赞 TODO 按照点赞量排序（6期做）
            // 当前用户点赞过，设置已点赞
            if (bizLiked.contains(rOra.getId())) {
                vo.setLiked(true);
            }

            // 评论回复特有的目标用户命信息
            if (itsReply && rOra.getTargetReplyId() != null) {
                UserDTO targetUserInfo = userInfoMap.get(rOra.getTargetUserId());
                if (targetUserInfo != null) {
                    vo.setTargetUserName(targetUserInfo.getName());
                }
            }

            // 用户
            // 匿名则将userId设置为空，用户信息自然也无需设置，直接跳出当前循环
            if (rOra.getAnonymity()) {
                vo.setUserId(null);
                voList.add(vo);
                continue;
            }
            // 用户信息
            UserDTO nowUserInfo = userInfoMap.get(rOra.getUserId());
            if (nowUserInfo != null) {
                vo.setUserName(nowUserInfo.getName());
                vo.setUserIcon(nowUserInfo.getIcon());
                vo.setUserType(nowUserInfo.getType());
            }
            voList.add(vo);
        }
        return PageDTO.of(page, voList);
    }

    /**
     * 管理端分页查询问题下的回答或者评论
     */
    @Override
    public PageDTO<ReplyVO> queryAnswerOrReplyAdmin(ReplyPageQuery query) {
        // 条件分页查询
        LambdaQueryWrapper<InteractionReply> wrapper = this.buildAnswerOrReplyWrapper(query, true);
        Page<InteractionReply> page = this.page(query.toMpPageDefaultSortByCreateTimeDesc(), wrapper);
        // 获取回答或者评论数据
        List<InteractionReply> repliesOrAnswers = page.getRecords();
        // 空直接返回
        if (CollUtils.isEmpty(repliesOrAnswers)) {
            return PageDTO.empty(page);
        }

        // 取出用户id 调用user-service查出用户信息  对于评论有特有的targetUserId需要查出targetUserName
        Boolean itsReply = query.getAnswerId() != null && query.getQuestionId() == null;
        Map<Long, UserDTO> userInfoMap = getUserInfoMapByUserIds(repliesOrAnswers, itsReply);

        // 取出所有的评论或者回答ID，调用远程微服务，判断当前用户是否点过赞
        Set<Long> bizLiked = this.isBizUserLiked(repliesOrAnswers);

        // 封装vo
        List<ReplyVO> voList = new ArrayList<>();
        for (InteractionReply rOra : repliesOrAnswers) {
            // 拷贝
            ReplyVO vo = BeanUtils.copyBean(rOra, ReplyVO.class);
            // 点赞 TODO 按照点赞量排序（6期做）
            // 当前用户点赞过，设置已点赞
            if (bizLiked.contains(rOra.getId())) {
                vo.setLiked(true);
            }

            // 评论回复特有的目标用户命信息
            if (itsReply && rOra.getTargetReplyId() != null) {
                UserDTO targetUserInfo = userInfoMap.get(rOra.getTargetUserId());
                if (targetUserInfo != null) {
                    vo.setTargetUserName(targetUserInfo.getName());
                }
            }
            // 用户信息
            UserDTO nowUserInfo = userInfoMap.get(rOra.getUserId());
            if (nowUserInfo != null) {
                vo.setUserName(nowUserInfo.getName());
                vo.setUserIcon(nowUserInfo.getIcon());
                vo.setUserType(nowUserInfo.getType());
            }
            voList.add(vo);
        }
        return PageDTO.of(page, voList);
    }

    /**
     * 根据用户id来查询用户信息
     */
    private Map<Long, UserDTO> getUserInfoMapByUserIds(List<InteractionReply> repliesOrAnswers,
                                                       Boolean itsReply) {
        Set<Long> userIds = new HashSet<>();
        repliesOrAnswers.forEach(
                interactionReply -> {
                    Long userId = interactionReply.getUserId();
                    userIds.add(userId);
                    if (itsReply) {
                        Long targetUserId = interactionReply.getTargetUserId();
                        userIds.add(targetUserId);
                    }
                }
        );
        userIds.remove(null);
        List<UserDTO> userInfos = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userInfoMap = new HashMap<>();
        if (CollUtils.isNotEmpty(userInfos)) {
            userInfoMap = userInfos.stream()
                    .collect(Collectors.toMap(UserDTO::getId, u -> u));
        }
        return userInfoMap;
    }


    /**
     * 检查分页查询回答或评论的参数
     * 返回是查评论还是回答
     */
    private Map<String, Boolean> checkPageQueryAndReturnFlag(ReplyPageQuery query) {
        // 查评论需要answerID
        Long answerId = query.getAnswerId();
        // 查回答需要questionID
        Long questionId = query.getQuestionId();
        if (answerId == null && questionId == null) {
            throw new BadRequestException("非法参数{问题ID和回复ID不能都为空}");
        }

        boolean itsReply = answerId != null && questionId == null;
        boolean itsAnswer = questionId != null && answerId == null;

        Map<String, Boolean> resultMap = new HashMap<>();
        resultMap.put("itsReply", itsReply);
        resultMap.put("itsAnswer", itsAnswer);
        return resultMap;
    }

    /**
     * 构造分页查询问题或评论wrapper
     */
    private LambdaQueryWrapper<InteractionReply> buildAnswerOrReplyWrapper(ReplyPageQuery query, Boolean isAdmin) {
        // 校验参数，并获取查询查询类型
        Map<String, Boolean> flagMap = checkPageQueryAndReturnFlag(query);
        boolean itsReply = flagMap.get("itsReply");
        boolean itsAnswer = flagMap.get("itsAnswer");

        // 构建wrapper
        LambdaQueryWrapper<InteractionReply> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(itsReply, InteractionReply::getAnswerId, query.getAnswerId())
                .eq(itsAnswer, InteractionReply::getQuestionId, query.getQuestionId())
                .eq(itsAnswer, InteractionReply::getTargetReplyId, 0)
                .eq(itsAnswer, InteractionReply::getAnswerId, 0);
        if (!isAdmin) {
            wrapper.eq(InteractionReply::getHidden, false);
        }
        return wrapper;
    }

    /**
     * 根据业务id（这里是评论或者回答的id）来查询当前用户是否点过赞
     */
    private Set<Long> isBizUserLiked(List<InteractionReply> repliesOrAnswers) {
        // 取出所有的评论或者回答ID，调用远程微服务，判断当前用户是否点过赞
        List<Long> bizIds = new ArrayList<>();
        repliesOrAnswers.forEach(
                interactionReply -> {
                    Long bizId = interactionReply.getId();
                    bizIds.add(bizId);
                }
        );
        Set<Long> bizLiked = likesClient.isBizLiked(bizIds);
        return bizLiked;
    }

}
